﻿using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq.Expressions;
using System.Reflection;
using System.Linq;

namespace SqlCommandHelper
{
    /// <summary>
    /// Sql Server stored procedure prameters builder
    /// </summary>
    /// <typeparam name="TEntity">TEntity</typeparam>
    public class StoredParameterBuilder<TEntity>
      where TEntity : class
    {
        #region Properties
        /// <summary>
        /// TModel 
        /// </summary>
        private TEntity Model { get; set; }

        /// <summary>
        /// Get Command
        /// </summary>
        private SqlCommand Command { get; set; }

        /// <summary>
        /// Parameters name
        /// </summary>
        private IList<string> PrametersName { get; set; }

        #endregion

        #region Constructur
        /// <summary>
        /// Create new instance of <see cref="StoredParameterBuilder"/> class.
        /// </summary>
        /// <param name="command">the Sql Command</param>
        /// <param name="model">the Model</param>
        public StoredParameterBuilder(SqlCommand command, TEntity model)
        {
            this.Model = model;
            this.Command = command;
            this.PrametersName = new List<string>();
        }

        #endregion

        #region methods

        /// <summary>
        /// Select Parameters to be set
        /// </summary>
        /// <typeparam name="TProperty">Properties</typeparam>
        /// <param name="selector">the selector</param>
        /// <returns>StoredParameterBuilder</returns>
        public StoredParameterBuilder<TEntity> Parameters<TProperty>(Expression<Func<TEntity, TProperty>> selector)
        {
            var members = (selector.Body as NewExpression).Members;
            foreach (var member in members)
            {
                this.PrametersName.Add(member.Name);
            }
            return this;
        }

        /// <summary>
        /// Build Parameters to Command
        /// </summary>
        public void Build()
        {
            Type type = this.Model.GetType();

            if (this.PrametersName.Count() == 0)
                this.PrametersName = this.GetDefaultParameters(type);

            foreach (string parameter in this.PrametersName)
            {
                PropertyInfo property = type.GetProperty(parameter);
                DbField dbField = (DbField)property.GetCustomAttribute(typeof(DbField));
                if (dbField != null && !string.IsNullOrEmpty(dbField.StoredProcedureParameterName))
                {
                    this.Command.Parameters.AddWithValue(dbField.StoredProcedureParameterName, property.GetValue(this.Model));
                }
            }
        }

        /// <summary>
        /// Set default stored parameters 
        /// </summary>
        /// <param name="type">current type</param>
        /// <returns>List of parameters.</returns>
        private IList<string> GetDefaultParameters(Type type)
        {
            return type.GetProperties().Select(c => c.Name).ToList();
        }

        #endregion
    }
}
